package com.ruoyi.web.controller.socket;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.SocketResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.SocketTypeEnum;
import com.ruoyi.framework.web.domain.server.Sys;
import com.ruoyi.question.domain.QAnswer;
import com.ruoyi.question.domain.QDoorRank;
import com.ruoyi.question.domain.QQuestion;
import com.ruoyi.question.domain.QZoom;
import com.ruoyi.question.enums.MatchStatusEnum;
import com.ruoyi.question.service.IQAnswerService;
import com.ruoyi.question.service.IQDoorRankService;
import com.ruoyi.question.service.IQQuestionService;
import com.ruoyi.question.service.IQZoomService;
import com.ruoyi.question.vo.MatchVo;
import com.ruoyi.question.vo.UserVo;
import com.ruoyi.system.service.ISysUserService;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@ServerEndpoint("/websocket/{zoomId}/{userId}")
@Component
public class WebSocketController {

    private static final  ConcurrentHashMap<Integer, List<Session>> sessions = new ConcurrentHashMap<>();
    private static final  ConcurrentHashMap<Integer, List<Session>> dataVSessions = new ConcurrentHashMap<>();

    private static final  ConcurrentHashMap<Integer, List<UserVo>> users = new ConcurrentHashMap<>();

    private static final  ConcurrentHashMap<Integer, MatchVo> matchVo = new ConcurrentHashMap<>();


//    private static final AtomicInteger onlineCount = new AtomicInteger(0);

    private static final int maxUser=6;
    private static final int maxScore=30; 

    private final static int maxIndex=3;
    private final static int maxQuestionCount=20;//一共20个题

    private static ISysUserService userService;
    private static IQQuestionService questionService;
    private static IQAnswerService answerService;
    private static IQDoorRankService doorRankService;
    private static IQZoomService zoomService;
    private UserVo user;
    private Session session;


    /**
     * 建立连接调用的方法
     */
    @OnOpen
    public void onOpen(Session session,@PathParam("zoomId") int zoomId,@PathParam("userId") long userId) {
//        if(sessions.contains(session)){
//            return;
//        }
        try {
            System.out.println("有客户端连接上");
            this.session = session;
            // 在线数增加
//        onlineCount.getAndIncrement();
            //如果是可视化大屏
            if (userId == 0) {
                if (dataVSessions.get(zoomId) == null) {
                    dataVSessions.put(zoomId, new ArrayList<>());
                }
                dataVSessions.get(zoomId).add(session);
                this.sendUserListByZoomId(zoomId);
                return;
            }
            if (sessions.get(zoomId) == null) {
                sessions.put(zoomId, new ArrayList<>());
            }
            if (sessions.get(zoomId).size() >= maxUser) {
                this.sendMaxCount();
            }
            List<Session> sessionList = sessions.get(zoomId);
            sessionList.add(session);
            //保存当前用户身份
            SysUser user = userService.selectUserById(userId);
            UserVo userVo = new UserVo();
            BeanUtil.copyProperties(user, userVo);
            this.user = userVo;
            if (users.get(zoomId) == null) {
                users.put(zoomId, new ArrayList<>());
            }
            if (matchVo.get(zoomId) == null) {
                MatchVo _matchVo = new MatchVo();
                _matchVo.setCurrentIndex(1);
                _matchVo.setStatus(MatchStatusEnum.COME);
                _matchVo.setUserList(users.get(zoomId));
                matchVo.put(zoomId, _matchVo);
            }
            users.get(zoomId).add(userVo);
            QZoom zoom = zoomService.lambdaQuery().select(QZoom::getIsOver).eq(QZoom::getId, zoomId).one();
            if (zoom == null) {
                this.not();
                return;
            }
            if (zoom.getIsOver()) {
                this.over();
                return;
            }
            this.sendUserListByZoomId(zoomId);
            this.sendMatchData(zoomId);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 客户端消息处理的方法
     */
    @OnMessage
    public void onMessage(String message,@PathParam("zoomId") Integer zoomId,@PathParam("userId") Long userId) {
        try{
        SocketResult data= JSONObject.parseObject(message,SocketResult.class);
        switch (data.getType()){
            case HEARTBEAT:
                System.out.println("收到心跳包");
                break;
            case READY:
//                user.setReady(true);
//                this.sendUserListByZoomId(zoomId);
//                //如果房间满员了,判断是否都准备了,准备了就开始比赛
//                if(users.get(zoomId).size()>=maxUser){
//                    for(UserVo _user:users.get(zoomId)){
//                        if(_user.isReady()==false){
//                            return;
//                        }
//                    }
//                    //获取当前是第几轮
//                    int index=JSONObject.from(data.getData()).getIntValue("index");
//                    this.start(zoomId,index);
//                }
                //获取当前是第几轮
                this.resetUsers(zoomId);
                this.sendUserListByZoomId(zoomId);
                int index=JSONObject.from(data.getData()).getIntValue("index");
                this.start(zoomId,index);
                break;
            case ANSWER:
                JSONObject _data=JSONObject.parseObject(data.getData().toString());
                //保留答题记录
                QAnswer answer=JSONObject.parseObject(_data.toString(),QAnswer.class);
                answer.setUserId(userId);
                answer.setCreateTime(new Date());
                answer.setZoomId(zoomId);
//                answerService.save(answer);
                //将答题分数保存,并推送给其他人
                this.user.setCount(this.user.getCount()+1);
                if(answer.getResult()){
                    this.user.setRightCount(this.user.getRightCount()+1);
                }else{
                    this.user.setErrorCount(this.user.getErrorCount()+1);
                }
                this.user.setScore(this.user.getScore()+answer.getScore());
                this.user.setQuestionIndex(_data.getIntValue("questionIndex"));
                this.sendAnswerDataV(zoomId,answer);
                this.sendUserListByZoomId(zoomId);
                //判断是否已经到100分,如果到100分,就通知其他选手不用答题了
                if(this.user.getScore()>=maxScore){
                    this.overAnswer(zoomId,answer.getIndex());
                }
                boolean sendFlag=false;
                for(UserVo userVo:users.get(zoomId)){
                    if(userVo.getQuestionIndex()<maxQuestionCount){
//                        return;
                        sendFlag=true;
                    }
                }
                if(sendFlag==false){
                    this.overAnswer(zoomId,answer.getIndex());
                }
                break;
            case OVERTIME:
                int _index=JSONObject.from(data.getData()).getIntValue("index");
                this.overAnswer(zoomId,_index);
                break;
            case OVERTIMECANCEL:
//                this.overTimeCancel(zoomId);
                break;
        }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 关闭连接调用的方法
     */
    @OnClose
    public void onClose(Session session,@PathParam("zoomId") int zoomId,@PathParam("userId") long userId) {
        // 在线数减少
        System.out.println("有客户端断开");
//        onlineCount.getAndDecrement();
        //如果是用户断连
        if(userId!=0){
            sessions.get(zoomId).remove(session);
            if(users.get(zoomId)==null){
                return;
            }
            users.get(zoomId).remove(user);
            this.sendUserListByZoomId(zoomId);
        }else{
            //如果可视化断连
            dataVSessions.get(zoomId).remove(session);
        }
    }

    private void over(){
        String data=SocketResult.ok(SocketTypeEnum.OVER,SocketTypeEnum.OVER.getName());
        this.sendMessage(data);
    }
    //房间不存在
    private void not(){
        String data=SocketResult.ok(SocketTypeEnum.NOT,SocketTypeEnum.NOT.getName());
        this.sendMessage(data);
    }

    private void sendAnswerDataV(Integer zoomId,QAnswer answer){
        String data=SocketResult.ok(SocketTypeEnum.ANSWER,answer);
        this.sendDataVMessage(zoomId,data);
    }

    //发送人数情况
    private void sendUserListByZoomId(Integer zoomId){
        String data=SocketResult.ok(SocketTypeEnum.ZOOMUSERLIST,users.get(zoomId));
        this.sendMessage(zoomId,data);
        this.sendUserListForDataV(zoomId,data);
    }

    private void sendMatchData(Integer zoomId){
        String data=SocketResult.ok(SocketTypeEnum.MATCHDATA,matchVo.get(zoomId));
        this.sendMessage(data);
    }

    private void sendUserListForDataV(Integer zoomId,String data){
        //通知可视化大屏
        if(dataVSessions.get(zoomId)!=null){
            try{
                for(Session _session:dataVSessions.get(zoomId)){
                    _session.getBasicRemote().sendText(data);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }
    }

    private void overAnswer(Integer zoomId,int index){
            matchVo.get(zoomId).setStatus(MatchStatusEnum.OVER);
            List<QDoorRank> doorRanks=new ArrayList<>();
            for(UserVo userVo:users.get(zoomId)){
                QDoorRank doorRank=new QDoorRank();
                BeanUtil.copyProperties(userVo,doorRank);
                doorRank.setIndex(index);
                doorRank.setZoomId(zoomId);
                doorRanks.add(doorRank);
            }
            doorRanks=this.rankScore(doorRanks);
            //保存数据进数据库
//        doorRankService.saveBatch(doorRanks);

            JSONObject rs=new JSONObject();
            rs.put("doorRanks",doorRanks);
            String data=SocketResult.ok(SocketTypeEnum.OVER_ANSWER,rs);
            this.sendMessage(zoomId,data);
            this.sendDataVMessage(zoomId,data);
    }

    private void overTimeCancel(int zoomId){
        String data=SocketResult.ok(SocketTypeEnum.OVERTIMECANCEL);
        this.sendMessage(zoomId,data);
        this.sendDataVMessage(zoomId,data);
    }
    private List<QDoorRank> rankScore(List<QDoorRank> doorRanks){
        //根据分数排序
        doorRanks = doorRanks.stream().sorted(Comparator.comparingInt(QDoorRank::getScore).reversed()).collect(Collectors.toList());
//        doorRanks = ListUtil.sortByProperty(doorRanks, "score");
        //判断是否有重复的排名
//        Map<Integer,Integer> rankMap=new HashedMap();
//        for(int i=0;i<doorRanks.size();i++){
//            //判断分数有没有重复的
//            if(rankMap.get(doorRanks.get(i).getScore())==null){
//                rankMap.put(doorRanks.get(i).getScore(),i);
//                doorRanks.get(i).setRank(i+1);
//            }else{
//                doorRanks.get(i).setRank(rankMap.get(doorRanks.get(i).getScore()));
//            }
//        }
        for(int i=0;i<doorRanks.size();i++){
            doorRanks.get(i).setRank(i+1);
        }
        return doorRanks;
    }

    private void resetUsers(Integer zoomId){
        //比赛开始后,重新设置队员不准备
        for(UserVo userVo:users.get(zoomId)){
            userVo.setReady(false);
            userVo.setRightCount(0);
            userVo.setCount(0);
            userVo.setErrorCount(0);
            userVo.setScore(0);
            userVo.setQuestionIndex(0);
        }
    }
    //人数已满
    private void sendMaxCount(){
        String data=SocketResult.ok(SocketTypeEnum.MAXUSER);
        this.sendMessage(data);
    }
    private void start(Integer zoomId,int index){
        String data=null;
        matchVo.get(zoomId).setStatus(MatchStatusEnum.START);
        matchVo.get(zoomId).setCurrentIndex(index);
        //如果是第1轮比赛,就发送问题列表
        if(index==1){
            List<QQuestion> questions=questionService.lambdaQuery().orderByAsc(QQuestion::getSort).last("limit "+maxQuestionCount*maxIndex).list();
            data=SocketResult.ok(SocketTypeEnum.START,questions,index);
            zoomService.lambdaUpdate().set(QZoom::getStartTime,new Date())
                    .eq(QZoom::getId,zoomId).update();
        }else{
            data=SocketResult.ok(SocketTypeEnum.START,new ArrayList<>(),index);
        }
        this.sendMessage(zoomId,data);
        this.sendDataVMessage(zoomId,data);

    }



    /**
     * 发生错误调用的方法
     */
    @OnError
    public void onError(Session session, Throwable throwable) throws Exception {
        System.out.println("发生websocket错误!");
        System.out.println(throwable.getMessage());
//        session.getBasicRemote().sendText(throwable.getMessage());
    }

    //通知房间所有人
    public void sendMessage(Integer zoomId,String message) {
        if(sessions.get(zoomId)!=null){
            try {
                for(Session _session:sessions.get(zoomId)){
                    _session.getBasicRemote().sendText(message);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void sendDataVMessage(Integer zoomId,String message) {
        if(dataVSessions.get(zoomId)!=null){
            try {
                for(Session _session:dataVSessions.get(zoomId)){
                    _session.getBasicRemote().sendText(message);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void sendMessage(String message) {
        try {
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Autowired
    public void setUserService(ISysUserService _userService){
        userService=_userService;
    }
    @Autowired
    public void setQuestionService(IQQuestionService _questionService){
        questionService=_questionService;
    }
    @Autowired
    public void setAnswerService(IQAnswerService _answerService){
        answerService=_answerService;
    }
    @Autowired
    public void setDoorRankService(IQDoorRankService _doorRankService){
        doorRankService=_doorRankService;
    }
    @Autowired
    public void setZoomService(IQZoomService _zoomService){
        zoomService=_zoomService;
    }
}
